#pragma once
#include "util.hpp"
#include <unordered_map>
/*
session 管理模块
管理用户登录，存储session ID
*/
enum ss_statu
{
    UNLOGIN,
    LONGIN
};

class session
{
public:
    session(uint64_t ssid, uint64_t uid)
        : _ssid(ssid),
          _uid(uid)
    {
        LOG(INFO, "session create success\n");
    }
    ~session()
    {
        LOG(INFO, "session close success\n");
    }
    uint64_t ssid() { return _ssid; }
    uint64_t uid() { return _uid; }
    void set_statu(int statu) { _statu = statu; }
    void set_timer(const wsserver_t::timer_ptr &tp) { _tp = tp; }
    wsserver_t::timer_ptr &get_timer() { return _tp; }

private:
    uint64_t _ssid;
    uint64_t _uid;
    int _statu;                // 用户状态：未登录，已登录
    wsserver_t::timer_ptr _tp; // session关联的定时器
};

#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
using session_ptr = std::shared_ptr<session>;
class session_manager
{
public:
    session_manager(wsserver_t *srv) : _next_ssid(1), _server(srv)
    {
        LOG(INFO,"session manager create success\n");
    }
    session_ptr create_session(uint64_t uid, int statu)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        session_ptr ssp = std::make_shared<session>(_next_ssid, uid);
        ssp->set_statu(statu);
        _sessions.insert({_next_ssid, ssp});
        _next_ssid++;
        return ssp;
    }
    session_ptr get_session_by_sid(uint64_t sid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto pos = _sessions.find(sid);
        if (pos == _sessions.end())
            return session_ptr();
        return pos->second;
    }
    void append_session(const session_ptr &ssp)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _sessions.insert({ssp->ssid(), ssp});
    }

    void remove_session(uint64_t sid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _sessions.erase(sid);
    }

    void set_session_expired_time(uint64_t sid, int msec)
    {
        //std::unique_lock<std::mutex> lock(_mutex);
        session_ptr ssp = get_session_by_sid(sid); //这里死锁了！！！！靠！！！
        if (ssp.get() == nullptr)
            return;

        wsserver_t::timer_ptr tp = ssp->get_timer();
        if (tp.get() == nullptr && msec == SESSION_FOREVER)
        {
            return;
        }
        else if (tp.get() == nullptr && msec != SESSION_FOREVER)
        {
            wsserver_t::timer_ptr tmp_time = _server->set_timer(msec, std::bind(&session_manager::remove_session, this, sid));
            ssp->set_timer(tmp_time);
        }
        else if (tp.get() != nullptr && msec == SESSION_FOREVER)
        {
            tp->cancel();
            ssp->set_timer(wsserver_t::timer_ptr());
            _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp));
        }
        else if (tp.get() != nullptr && msec != SESSION_FOREVER)
        {
            // 重新设置定时任务
            // 先取消之前的任务
            tp->cancel();
            ssp->set_timer(wsserver_t::timer_ptr());
            _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp));
            // 重新添加任务
            wsserver_t::timer_ptr tmp_time = _server->set_timer(msec, std::bind(&session_manager::remove_session, this, sid));
            ssp->set_timer(tmp_time);
        }
    }

private:
    std::mutex _mutex;
    wsserver_t *_server;
    uint64_t _next_ssid;

    /*session id <-> session_ptr*/
    std::unordered_map<uint64_t, session_ptr> _sessions;
};